package com.Register.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.Register.context.BaseContext;
import com.Register.dto.*;
import com.Register.entity.SkillDocument;
import com.Register.entity.User;
import com.Register.mapper.SkillDocumentMapper;
import com.Register.result.PageResult;
import com.Register.result.Result;
import com.Register.service.SkillDocumentService;
import com.Register.service.UserService;
import com.Register.vo.SkillDocumentVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

import static com.Register.constant.RedisConstant.*;


@Service
public class SkillDocumentServiceImpl extends ServiceImpl<SkillDocumentMapper, SkillDocument> implements SkillDocumentService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private ObjectMapper objectMapper = new ObjectMapper();

    @Resource
    private SkillDocumentMapper skillDocumentMapper;

    @Resource
    private UserService service;

    @Override
    public List<Long> getAllSkillDocumentIds() {
        return skillDocumentMapper.getAllActiveId();
    }

    @Override
    public void updateSkillDocumentViewCount(Long skillDocumentId, Long viewCount) {
        skillDocumentMapper.updateActiveDocViews(skillDocumentId,viewCount);
    }

    /*
        创建技能培训文章
         */
    @Override
    @Transactional
    public Result<String> createSkillDocument(SkillDocumentCreateDTO skillDocumentDTO) throws JsonProcessingException {
        User user=service.getById(BaseContext.getCurrentId());
        //设置基本信息
        SkillDocument skillDocument=new SkillDocument();
        skillDocument.setCreateTime(LocalDateTime.now());
        skillDocument.setCreateUser(BaseContext.getCurrentId());
        //拷贝属性
        BeanUtil.copyProperties(skillDocumentDTO,skillDocument);
        SkillDocumentDTO skillDocumentDTO1 = new SkillDocumentDTO();
        BeanUtil.copyProperties(skillDocumentDTO,skillDocumentDTO1);
        skillDocumentDTO1.setCreateTime(LocalDateTime.now());
        skillDocumentDTO1.setOrganization(user.getOrganization());

        skillDocument.setOrganization(user.getOrganization());
        //保存到数据库
        save(skillDocument);
        //添加到redis中
        stringRedisTemplate.opsForValue().set(skillDocumentInfo+skillDocument.getId().toString(),objectMapper.writeValueAsString(skillDocumentDTO1));
        //设置浏览数数据
        stringRedisTemplate.opsForValue().set(getSkillDocumentViews+skillDocument.getId(),String.valueOf(0L));
        stringRedisTemplate.opsForList().leftPush(skillDocumentIdList,skillDocument.getId().toString());
        return Result.success("创建技能培训文章成功");
    }

    /*
    分页查询开放的文章
     */
    @Override
    public PageResult getActiveSkillDocument(SkillDocumentPageQueryDTO skillDocumentPageQueryDTO) throws JsonProcessingException {
        Long pageNo = skillDocumentPageQueryDTO.getPageNo();
        Long pageSize = skillDocumentPageQueryDTO.getPageSize();
        // 获取文章id列表的范围
        List<String> idList = stringRedisTemplate.opsForList().range(skillDocumentIdList, (pageNo - 1) * pageSize, pageNo * pageSize - 1);
        // 如果id列表为空，返回分页结果
        if (idList == null || idList.isEmpty()) {
            return new PageResult(0L, 0L, Collections.emptyList());
        }
        // 根据活动id获取活动详情
        List<SkillDocumentDTO> skillDocumentDTOList = new ArrayList<>();
        for (String id : idList) {
            String documentKey = skillDocumentInfo + id;
            String cachedDocument = stringRedisTemplate.opsForValue().get(documentKey);
            SkillDocumentDTO skillDocumentDTO = null;

            if (cachedDocument != null) {
                skillDocumentDTO = objectMapper.readValue(cachedDocument, SkillDocumentDTO.class);
                skillDocumentDTO.setViews(Long.valueOf(Objects.requireNonNull(stringRedisTemplate.opsForValue().
                        get(getSkillDocumentViews + id))));
            } else {
                // 如果缓存中没有该数据就去数据库中查找
                LambdaQueryWrapper<SkillDocument> skillDocumentLambdaQueryWrapper = new LambdaQueryWrapper<>();
                skillDocumentLambdaQueryWrapper
                        .eq(SkillDocument::getId, id)
                        .eq(SkillDocument::getActiveStatus, true)
                        .like(skillDocumentPageQueryDTO.getTitle() != null,
                                SkillDocument::getTitle, skillDocumentPageQueryDTO.getTitle())
                        .eq(skillDocumentPageQueryDTO.getTag() != null,
                                SkillDocument::getTag, skillDocumentPageQueryDTO.getTag());
                SkillDocument skillDocument = getOne(skillDocumentLambdaQueryWrapper);
                if (skillDocument != null) {
                    skillDocumentDTO = SkillDocumentDTO.builder()
                            .title(skillDocument.getTitle())
                            .tag(skillDocument.getTag())
                            .description(skillDocument.getDescription())
                            .fileUrl(skillDocument.getFileUrl())
                            .imageUrl(skillDocument.getImageUrl())
                            .organization(skillDocument.getOrganization())
                            .createTime(skillDocument.getCreateTime())
                            .build();
                    String viewsStr = stringRedisTemplate.opsForValue().get(getSkillDocumentViews + skillDocument.getId());
                    Long views = null;
                    if (viewsStr != null) {
                        try {
                            views = Long.valueOf(viewsStr);
                        } catch (NumberFormatException e) {
                            // 处理格式错误的情况（例如如果 Redis 存储了非数字的值）
                        }
                    }

                    if (views == null) {
                        skillDocumentDTO.setViews(skillDocument.getViews());
                    } else {
                        skillDocumentDTO.setViews(views);
                    }

                    // 加入redis缓存，方便下次查询
                    stringRedisTemplate.opsForValue().set(documentKey,
                            objectMapper.writeValueAsString(skillDocumentDTO));
                }
            }

            if (skillDocumentDTO != null) {
                // 动态筛选
                if (isMatching(skillDocumentPageQueryDTO, skillDocumentDTO)) {
                    // 切分tag字段为数组
                    skillDocumentDTO.setTag(
                            Arrays.asList(skillDocumentDTO.getTag().split("[,，]")).toString() // 使用中英文逗号切分
                    );
                    skillDocumentDTOList.add(skillDocumentDTO);
                }
            }
        }

        // 返回分页结果
        Long size = stringRedisTemplate.opsForList().size(skillDocumentIdList);
        assert size != null;
        Long pages = (size + pageSize - 1) / pageSize;
        return new PageResult(pages, size, skillDocumentDTOList);
    }


    /*
    管理员分页查询所有文章
     */
    @Override
    public PageResult getAllSkillDocument(AdminSkillDocumentPageQueryDTO adminSkillDocumentPageQueryDTO) {
        //构建分页条件
        Page<SkillDocument> page=adminSkillDocumentPageQueryDTO.toMpPageDefaultSortByCreateTimeDesc();

        //构建查询条件
        LambdaQueryWrapper<SkillDocument> lambdaQueryWrapper=new LambdaQueryWrapper<>();

        lambdaQueryWrapper
                .eq(adminSkillDocumentPageQueryDTO.getActiveStatus()!=null,
                        SkillDocument::getActiveStatus,adminSkillDocumentPageQueryDTO.getActiveStatus())
                .like(adminSkillDocumentPageQueryDTO.getTitle()!=null,
                        SkillDocument::getTitle,adminSkillDocumentPageQueryDTO.getTitle())
                .eq(adminSkillDocumentPageQueryDTO.getDeleted()!=null,
                        SkillDocument::getDeleted,adminSkillDocumentPageQueryDTO.getDeleted())
                .eq(adminSkillDocumentPageQueryDTO.getTag()!=null,
                        SkillDocument::getTag,adminSkillDocumentPageQueryDTO.getTag());
        Page<SkillDocument> skillDocumentPage = skillDocumentMapper.selectPage(page, lambdaQueryWrapper);
        //总页数
        long pages = skillDocumentPage.getPages();
        //总记录数
        long total = skillDocumentPage.getTotal();
        //当前页数据
        List<SkillDocument> records = skillDocumentPage.getRecords();
        return new PageResult(pages,total,records);
    }

    /*
    管理员更新技能培训文档
     */
    @Override
    @Transactional
    public Result<String> updateSkillDocument(SkillDocumentUpdateDTO skillDocumentUpdateDTO) {
        //获取修改对象
        SkillDocument skillDocument=getById(skillDocumentUpdateDTO.getId());
        //设置更新字段
        skillDocument.setUpdateTime(LocalDateTime.now());
        skillDocument.setUpdateUser(BaseContext.getCurrentId());

        //更新缓存
        if(skillDocumentUpdateDTO.getDeleted()!=null&&skillDocumentUpdateDTO.getDeleted()==1L){
            skillDocumentMapper.deleteById(skillDocumentUpdateDTO.getId());
            //删除对应的缓存
            stringRedisTemplate.opsForList().remove(skillDocumentIdList,0,skillDocumentUpdateDTO.getId().toString());
            //浏览数缓存
            String redisKey = "DocumentViews" + skillDocument.getId();
            stringRedisTemplate.delete(redisKey);
            return Result.success("删除成功");
        }
        //如果恢复展示了
        if(skillDocumentUpdateDTO.getActiveStatus()!=null&&
                skillDocumentUpdateDTO.getActiveStatus()&&
                !skillDocument.getActiveStatus()){
            stringRedisTemplate.opsForList().leftPush(skillDocumentIdList,skillDocument.getId().toString());
            //恢复浏览数缓存
            stringRedisTemplate.opsForValue().set(getSkillDocumentViews+skillDocument.getId()
                    ,String.valueOf(skillDocument.getViews()));
        }
        //如果不展示了
        if(skillDocumentUpdateDTO.getActiveStatus()!=null&&!skillDocumentUpdateDTO.getActiveStatus()){
            //移除展示列表
            stringRedisTemplate.opsForList().remove(skillDocumentIdList,0,skillDocumentUpdateDTO.getId().toString());
            //浏览数缓存
            String redisKey = "DocumentViews" + skillDocument.getId();
            stringRedisTemplate.delete(redisKey);
        }
        //删除对应的redis缓存
        stringRedisTemplate.delete(skillDocumentInfo+skillDocument.getId().toString());
        //写入数据库
        BeanUtil.copyProperties(skillDocumentUpdateDTO,skillDocument);
        updateById(skillDocument);
        return Result.success("更新成功");
    }

    /*
    根据id查询文章
     */
    @Override
    public SkillDocument getDocumentByid(String id) {
        return getById(id);
    }

    /*
    用户点击查看文章
     */
    @Override
    public SkillDocumentVO viewDoc(Long id) throws JsonProcessingException {
        //更新点击数缓存
        stringRedisTemplate.opsForValue().increment(getSkillDocumentViews+id);
        String documentKey = skillDocumentInfo + id;
        String cachedDocument = stringRedisTemplate.opsForValue().get(documentKey);
        new SkillDocumentDTO();
        SkillDocumentDTO skillDocumentDTO;
        //返回给前端
        if(cachedDocument!=null){
            skillDocumentDTO = objectMapper.readValue(cachedDocument, SkillDocumentDTO.class);
            return SkillDocumentVO.builder()
                    .fileUrl(skillDocumentDTO.getFileUrl())
                    .imageUrl(skillDocumentDTO.getImageUrl())
                    .build();
        }else {
            SkillDocument skillDocument=getById(id);
            return SkillDocumentVO.builder()
                    .fileUrl(skillDocument.getFileUrl())
                    .imageUrl(skillDocument.getImageUrl())
                    .build();
        }
    }

    /*
    动态筛选分页内容
     */
    private boolean isMatching(SkillDocumentPageQueryDTO skillDocumentPageQueryDTO,SkillDocumentDTO skillDocumentDTO){
        return (skillDocumentPageQueryDTO.getTag()==null||skillDocumentDTO.getTag().contains(skillDocumentPageQueryDTO.getTag()))
                &&(skillDocumentPageQueryDTO.getTitle()==null||skillDocumentDTO.getTitle().contains(skillDocumentPageQueryDTO.getTitle()));
    }
}
